import { Component, ChangeDetectorRef, OnInit, ViewChild, TemplateRef } from '@angular/core';
import { AbstractControl, FormArray, FormControl, FormGroup, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { AfMessageService, AfNavigationService, AfSecurityService, AfUpDownService } from '@core';
import { ModalHelper } from '@delon/theme';
import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd/dropdown';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzTreeComponent, NzFormatEmitEvent, NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/tree';
import { NzTreeSelectComponent } from 'ng-zorro-antd/tree-select';
import { AfExcelService, ExcelUploadRecord } from 'src/app/routes/system/excel/af-excel.service';

import { CodeGenService } from '../../codegen.service';
import { LangDBScriptComponent } from '../../lang/db-script/lang-db-script.component';
import { LangJpaScriptComponent } from '../../lang/jpa-script/lang-jpa-script.component';
import { ActionType, LangSourceType } from '../../lang/lang';
import { NodeType, SourceType, DruidDbTypes, ColumnForm, ConstraintForm, DataTypes, ConstraintTypes, FolderNode } from '../meta-info';

@Component({
  selector: 'app-cg-meta-view',
  templateUrl: './meta-view.component.html',
  styleUrls: ['./meta-view.component.less']
})
export class MetaViewComponent implements OnInit {
  @ViewChild('nzTreeComponent', { static: false }) nzTreeComponent!: NzTreeComponent;
  @ViewChild('nzTreeSelect', { static: false }) nzTreeSelect!: NzTreeSelectComponent;

  dataTypes = DataTypes;
  constraintTypes = ConstraintTypes;
  nodeTree: any[] = [];
  tmTree: any[] = [];

  currentNodeData: any = this.newFolderNode();
  currentPNodeData: any;
  dbSourceOptions: any[] = [];
  dbSources: any[] | null = null;
  searchTreeValue = '';

  constructor(
    private router: Router,
    private modal: ModalHelper,
    private codegen: CodeGenService,
    private cdr: ChangeDetectorRef,
    private msgSrv: AfMessageService,
    private modalSrv: NzModalService,
    private excelSrv: AfExcelService,
    private updownSrv: AfUpDownService,
    private securitySrv: AfSecurityService,
    private nzContextMenuService: NzContextMenuService
  ) {}

  ngOnInit(): void {
    this.getWorkspace();
    this.initDataTypes();
    this.cdr.detectChanges();
  }

  initDataTypes() {
    this.codegen.getUnifiedDataTpe().subscribe(res => {
      if (res.status) {
        this.dataTypes = res.data;
      }
    });
  }

  newFolderNode(): FolderNode {
    return {
      key: '',
      title: '',
      id: '',
      pid: '0',
      workspaceId: 0,
      type: NodeType.folder,
      name: '',
      remark: ''
    };
  }

  isLoading = false;
  workspaces: any[] = [];
  currentWsId: any;
  getWorkspace() {
    this.codegen.findWorkspaceByUser(this.securitySrv.userName).subscribe(body => {
      this.isLoading = false;
      console.log(body);
      if (body.status) {
        this.workspaces = body.data;
        if (this.workspaces && this.workspaces.length >= 1) {
          this.currentWsId = this.workspaces[0].id;
          this.queryNodeTree();
        }
      }
    });
  }

  queryNodeTree() {
    this.isLoading = true;
    this.nodeTree = [];
    this.codegen.queryFolderTree(this.currentWsId).subscribe(body => {
      console.log(body);
      this.isLoading = false;
      if (body.status) {
        this.nodeTree = body.data;
      }
    });
  }

  treeNodeDbClick(event: NzFormatEmitEvent): void {
    if (event.node?.origin['type'] == NodeType.table) {
      this.currentNodeData = event.node?.origin;
      this.queryTableInfo();
    }
  }

  nzParentNode: NzTreeNode | undefined | null;
  nzNode: NzTreeNode | undefined | null;

  treeNodeClick(event: NzFormatEmitEvent): void {
    this.nzNode = event.node;
    this.nzParentNode = event.node?.parentNode;
    if (this.nzNode?.origin['type'] == NodeType.table) {
      if (this.currentNodeData.key != this.nzNode?.key) {
        this.resetForm();
        this.tableInfoForm.controls.tableId.patchValue(this.nzNode?.key);
        this.tableInfoForm.controls.tableName.patchValue(this.nzNode?.title);
      }
    }
    this.currentNodeData = this.nzNode?.origin;
    this.currentPNodeData = this.nzParentNode?.origin;
  }

  editedParentTitle: any;
  editedNodeTitle: any;

  loading: Boolean = false;

  resetForm() {
    this.tableInfoForm.reset();
    this.tableInfoForm.controls.columns.clear();
    this.tableInfoForm.controls.constraints.clear();
  }

  tableInfoForm = new FormGroup({
    tableId: new FormControl(''),
    folderId: new FormControl('', { nonNullable: true, validators: [Validators.required] }),
    tableName: new FormControl('', { nonNullable: true, validators: [Validators.required] }),
    tableComment: new FormControl('', { nonNullable: true, validators: [Validators.required] }),
    sourceType: new FormControl(SourceType.input, { nonNullable: true, validators: [Validators.required] }),
    sourceName: new FormControl(''),
    remark: new FormControl(''),
    columns: new FormArray<FormGroup<ColumnForm>>([]),
    constraints: new FormArray<FormGroup<ConstraintForm>>([])
  });

  get columns(): FormArray<FormGroup<ColumnForm>> {
    return this.tableInfoForm.controls.columns;
  }
  get constraints(): FormArray<FormGroup<ConstraintForm>> {
    return this.tableInfoForm.controls.constraints;
  }

  getTableName() {
    return this.tableInfoForm.controls['tableName'].value;
  }

  // columnIndex = -1;
  // editColumnData = {};
  createColumnFormGroup(): FormGroup<ColumnForm> {
    return new FormGroup({
      columnName: new FormControl('', { nonNullable: true, validators: [Validators.required] }),
      columnComment: new FormControl('', { nonNullable: true, validators: [Validators.required] }),
      dataType: new FormControl('', { nonNullable: true, validators: [Validators.required] }),
      length: new FormControl('', { nonNullable: false, validators: [] }),
      scale: new FormControl('', { nonNullable: false, validators: [] }),
      nullable: new FormControl(true, { nonNullable: true, validators: [Validators.required] }),
      dataDefault: new FormControl('', { nonNullable: false, validators: [] })
    });
  }

  currentClasses = {
    display: 'block',
    overflow: 'auto',
    height: `${window.innerHeight - 150}px`
  };

  initColumn: any[] = [];
  createConstraintFormGroup(): FormGroup<ConstraintForm> {
    return new FormGroup({
      constraintType: new FormControl('', { nonNullable: true, validators: [Validators.required] }),
      constraintName: new FormControl('', { nonNullable: true, validators: [Validators.required] }),
      columnList: new FormControl(this.initColumn, { nonNullable: true, validators: [Validators.required] }),
      pkAutoIncrement: new FormControl(false, { nonNullable: true, validators: [Validators.required] })
    });
  }

  queryTableInfo() {
    if (!this.currentNodeData.id) {
      return;
    }
    this.codegen.queryTableInfo(this.currentNodeData.id).subscribe(res => {
      this.loading = false;
      if (res.status) {
        this.setFormData(res.data);
      } else {
        this.msgSrv.notice_warning('', `${res.msg}`);
      }
    });
  }

  setFormData(body: any) {
    // console.log(body);
    this.tableInfoForm.patchValue(body.metaTable);
    if (body.metaColumns && body.metaColumns.length >= 1) {
      this.tableInfoForm.controls.columns.clear();
      body.metaColumns.forEach((col: any) => {
        const field = this.createColumnFormGroup();
        field.patchValue(col);
        this.tableInfoForm.controls.columns.push(field);
      });
    }

    if (body.metaConstraints && body.metaConstraints.length >= 1) {
      this.tableInfoForm.controls.constraints.clear();
      body.metaConstraints.forEach((col: any) => {
        const field = this.createConstraintFormGroup();
        field.patchValue(col);
        this.tableInfoForm.controls.constraints.push(field);
      });
    }
  }

  dbTypes: any[] = ['mysql', 'oracle', 'postgresql', 'sqlserver', 'maxcompute1', 'hologres', 'clickhouse', 'flink'];
  druidDbTypes: any[] = DruidDbTypes;
  dbType: any = '';

  // metaSql: any = '';

  selectTableId: any = '';
  newTableName: any;
  onTreeSelectChange($event: any): void {
    // this.selectTableId = $event;
    if (this.nzTreeSelect.getSelectedNodeList().length >= 1) {
      this.newTableName = `${this.nzTreeSelect.getSelectedNodeList()[0].title}_copy`;
    }
  }

  scriptDbType = 'mysql';
  namingRule = 'same';
  navigateDbScript() {
    if (this.currentNodeData.type == NodeType.folder) {
      this.msgSrv.msg_warning('请选择表节点');
      return;
    }
    if (!this.currentNodeData.id) {
      this.msgSrv.msg_warning('请选择表');
      return;
    }

    this.router.navigateByUrl(
      `/codegen/lang/db/script?actionType=${ActionType.view}&sourceType=${LangSourceType.meta}&sourceName=${this.currentPNodeData.title}&sourceLabel=${this.currentNodeData.title}&sourceTable=${this.currentNodeData.id}&namingRule=${this.namingRule}&scriptDbType=${this.scriptDbType}`
    );
  }

  navigateJpaScript() {
    if (this.currentNodeData.type == NodeType.folder) {
      this.msgSrv.msg_warning('请选择表节点');
      return;
    }
    if (!this.currentNodeData.id) {
      this.msgSrv.msg_warning('请选择表');
      return;
    }

    this.router.navigateByUrl(
      `/codegen/lang/jpa/script?sourceType=${LangSourceType.meta}&sourceName=${this.currentPNodeData.title}&sourceLabel=${this.currentNodeData.title}&sourceTable=${this.currentNodeData.id}&namingRule=${this.namingRule}&scriptDbType=${this.scriptDbType}`
    );
  }

  openDbScript() {
    if (this.currentNodeData.type == NodeType.folder) {
      this.msgSrv.msg_warning('请选择表节点');
      return;
    }
    if (!this.currentNodeData.id) {
      this.msgSrv.msg_warning('请选择表');
      return;
    }

    const record: any = {
      actionType: ActionType.view,
      sourceType: LangSourceType.meta,
      sourceName: this.currentPNodeData.title,
      sourceLabel: this.currentNodeData.title,
      sourceTable: this.currentNodeData.id,
      namingRule: this.namingRule,
      scriptDbType: this.scriptDbType
    };
    this.modal.create(LangDBScriptComponent, { record }, { size: 'xl' }).subscribe(res => {
      console.log(res);
    });
  }

  openJpaScript() {
    if (this.currentNodeData.type == NodeType.folder) {
      this.msgSrv.msg_warning('请选择表节点');
      return;
    }
    if (!this.currentNodeData.id) {
      this.msgSrv.msg_warning('请选择表');
      return;
    }

    const record: any = {
      sourceType: LangSourceType.meta,
      sourceName: this.currentPNodeData.title,
      sourceLabel: this.currentNodeData.title,
      sourceTable: this.currentNodeData.id,
      namingRule: this.namingRule,
      scriptDbType: this.scriptDbType
    };
    this.modal.create(LangJpaScriptComponent, { record }, { size: 'xl' }).subscribe(res => {
      console.log(res);
    });
  }

  treeContextMenu($event: MouseEvent, menu: NzDropdownMenuComponent): void {
    this.nzContextMenuService.create($event, menu);
  }

  exportColumnList() {
    let data = [['字段英文名', '字段中文名', '数据类型', '长度', '刻度', '可空', '默认值']];

    this.columns.controls.forEach(element => {
      const coldata = [
        element.controls.columnName.value as string,
        element.controls.columnComment.value as string,
        element.controls.dataType.value as string,
        element.controls.length.value as string,
        element.controls.scale.value as string,
        element.controls.nullable.value as any as string,
        element.controls.dataDefault.value as string
      ];
      data = [...data, coldata];
    });
    this.updownSrv.exportXlsx('xlsx', data, '字段列表', `${this.getTableName()}导出字段列表.xlsx`);
  }
}
